package com.open.xbus;


import android.os.Bundle;
import android.os.RemoteException;
import android.text.TextUtils;
import android.util.Log;

import com.google.gson.Gson;
import com.open.xbus.joor.Reflect;

import org.json.JSONArray;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

import static com.open.xbus.XBus.TAG;

public class XBusAidlImpl extends XBusAidl.Stub {

    private Gson gson = new Gson();
    // 用于保存回调，与pid对应
    private ConcurrentHashMap<Integer, IXBusCallback> mCallbacks = new ConcurrentHashMap<Integer, IXBusCallback>();

    @Override
    public Response run(Request request) throws RemoteException {
        if (XBus.IS_BUNDLE_DEBUG) {
            return runBundle(request);
        }
        return runJson(request);
    }

    /**
     * 注册回调，用于处理带回调的函数.
     */
    @Override
    public void register(IXBusCallback cb, int pid) throws RemoteException {
        mCallbacks.put(pid, cb);
        Log.d(TAG, "XBusAidlImpl register pid:" + pid);
    }

    /**
     * 使用 Bundle 处理 请求参数以及返回
     */
    private Response runBundle(Request request) {
        Bundle bundle = request.getBundle();
        Object[] bargs = (Object[]) bundle.getSerializable(Request.ARGS_KEY);
        String clazzName = bundle.getString(Request.CLAZZ_KEY);
        String method = bundle.getString(Request.METHOD_KEY);

        Response response = new Response();

        try {
            Class<?> iclazz = Reflect.on(clazzName).get();
            // 如果有回调存在，添加 动态代理支持.
            // Object[] mParameters 参考 Hermes->Receiver->setParameters
            Object createObject = XBus.getInstance().getCreateObject(iclazz);
            Object result = Reflect.on(createObject)
                                   .call(method, bargs).get();
            bundle.putSerializable(Response.RESULT_KEY, (Serializable) result);
        } catch (Exception e) {
            e.printStackTrace();
        }

        // 失败处理
        response.setBResult(bundle);
        return response;
    }

    /**
     * 使用 JSON 处理 请求参数以及返回
     */
    private Response runJson(Request request) {
        Response response = new Response();
        String data = request.getData();
        Request.ClassData classData = gson.fromJson(data, Request.ClassData.class);
        Log.d(TAG, "testCall request " + request);
        //
        try {
            List<Object> args = new ArrayList<>();
            // 类
            Class<?> iclazz = Class.forName(classData.clazz);
            Object createObject = XBus.getInstance().getCreateObject(iclazz);
            // 找到对应函数，后续需要一一对应类型.
            Method method = null;
            for (Method m : iclazz.getMethods()) {
                if (m.getName().equals(classData.method)) {
                    method = m;
                    break;
                }
            }
            // 将参数值与类型 保存到 args.
            if (!TextUtils.isEmpty(classData.params)) {
                Class<?>[] types = method.getParameterTypes(); // 获取参数列表
                JSONArray array = new JSONArray(classData.params);
                for (int i = 0; i < array.length(); i++) {
                    String o = array.getString(i);
                    // 比如 10, int  "testtest", String
                    args.add(gson.fromJson(o, types[i]));
                }
            }
            // 传入 args 参数，执行 method 函数
            Object result = Reflect.on(createObject)
                                   .call(classData.method, args.toArray(new Object[0])).get();
            // 返回
            response.setResult(gson.toJson(result));
            Log.d(TAG, "XBusAidlImpl run iclazz:" + iclazz + " createObject:" + createObject + " result:" + result);
            return response;
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 失败处理
        return response;
    }

}
